package com.library.management.entity;

import com.library.management.enums.ReservationStatus;
import jakarta.persistence.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

/**
 * 预约记录实体类
 * 管理用户对图书的预约请求
 *
 * 关联关系：
 * - 多对一：用户、图书
 *
 * 业务功能：
 * - 图书预约管理
 * - 预约有效期控制
 * - 预约通知处理
 *
 * @author 开发者
 * @version 1.0
 * @since 2025-10-19
 */
@Entity
@Table(name = "reservations", indexes = {
        @Index(name = "idx_reservations_user_id", columnList = "user_id"),
        @Index(name = "idx_reservations_book_id", columnList = "book_id"),
        @Index(name = "idx_reservations_status", columnList = "status"),
        @Index(name = "idx_reservations_expire_date", columnList = "expire_date")
})
@Data
@EqualsAndHashCode(exclude = {"user", "book"})
@ToString(exclude = {"user", "book"})
public class Reservation {

    // ========== 主键标识 ==========

    /**
     * 预约ID - 主键，自增长
     * 数据库字段：id (BIGINT, PRIMARY KEY, AUTO_INCREMENT)
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    // ========== 关联关系 ==========

    /**
     * 用户 - 预约者
     * 多对一关系，外键关联users表
     * 延迟加载提高性能
     */
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id", nullable = false, foreignKey = @ForeignKey(name = "fk_reservations_user_id"))
    private User user;

    /**
     * 图书 - 被预约的图书
     * 多对一关系，外键关联books表
     * 延迟加载提高性能
     */
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "book_id", nullable = false, foreignKey = @ForeignKey(name = "fk_reservations_book_id"))
    private Book book;

    // ========== 预约时间信息 ==========

    /**
     * 预约日期 - 预约创建时间
     * 数据库字段：reserve_date (DATETIME), NOT NULL
     */
    @Column(name = "reserve_date", nullable = false)
    private LocalDateTime reserveDate;

    /**
     * 过期日期 - 预约有效截止时间
     * 数据库字段：expire_date (DATETIME), NOT NULL
     */
    @Column(name = "expire_date", nullable = false)
    private LocalDateTime expireDate;

    // ========== 预约状态信息 ==========

    /**
     * 预约状态 - 当前预约状态
     * PENDING: 等待中，AVAILABLE: 可借阅，CANCELLED: 已取消，EXPIRED: 已过期
     * 数据库字段：status (ENUM), DEFAULT 'PENDING'
     */
    @Enumerated(EnumType.STRING)
    @Column(nullable = false, length = 20)
    private ReservationStatus status = ReservationStatus.PENDING;

    /**
     * 是否已发送通知 - 标记是否已发送可借阅通知
     * 数据库字段：notify_sent (TINYINT(1)), DEFAULT 0
     */
    @Column(name = "notify_sent")
    private Boolean notifySent = false;

    /**
     * 优先级 - 预约排队优先级（数字越小优先级越高）
     * 数据库字段：priority (INT), DEFAULT 0
     */
    private Integer priority = 0;

    // ========== 审计字段 ==========

    /**
     * 创建时间 - 记录创建时间，自动生成
     * 数据库字段：created_time (DATETIME), DEFAULT CURRENT_TIMESTAMP
     */
    @CreationTimestamp
    @Column(name = "created_time", updatable = false)
    private LocalDateTime createdTime;

    /**
     * 更新时间 - 记录最后修改时间，自动更新
     * 数据库字段：updated_time (DATETIME), DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
     */
    @UpdateTimestamp
    @Column(name = "updated_time")
    private LocalDateTime updatedTime;

    // ========== 业务方法 ==========

    /**
     * 检查预约是否已过期
     * 比较当前时间与过期日期
     *
     * @return true-已过期，false-未过期
     */
    public boolean isExpired() {
        return LocalDateTime.now().isAfter(this.expireDate) &&
                this.status == ReservationStatus.PENDING;
    }

    /**
     * 检查预约是否有效
     * 有效条件：状态为PENDING且未过期
     *
     * @return true-有效，false-无效
     */
    public boolean isValid() {
        return this.status == ReservationStatus.PENDING && !isExpired();
    }

    /**
     * 获取剩余有效天数
     * 从当前时间到过期日期的天数
     *
     * @return 剩余有效天数
     */
    public long getRemainingDays() {
        if (!isValid()) {
            return 0;
        }
        return ChronoUnit.DAYS.between(LocalDateTime.now(), this.expireDate);
    }

    /**
     * 取消预约
     * 将状态设置为已取消
     *
     * @return true-取消成功，false-取消失败
     */
    public boolean cancel() {
        if (this.status == ReservationStatus.PENDING) {
            this.status = ReservationStatus.CANCELLED;
            return true;
        }
        return false;
    }

    /**
     * 标记为可借阅
     * 当预约的图书可用时调用
     *
     * @return true-标记成功，false-标记失败
     */
    public boolean markAsAvailable() {
        if (this.status == ReservationStatus.PENDING) {
            this.status = ReservationStatus.AVAILABLE;
            return true;
        }
        return false;
    }

    /**
     * 检查是否即将过期（在指定天数内过期）
     *
     * @param days 提前提醒天数
     * @return true-即将过期，false-未即将过期
     */
    public boolean isExpiringSoon(int days) {
        if (!isValid()) {
            return false;
        }
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime warningDate = this.expireDate.minusDays(days);
        return !now.isBefore(warningDate) && now.isBefore(this.expireDate);
    }

    /**
     * 获取预约等待天数
     * 从预约日期到当前时间的天数
     *
     * @return 等待天数
     */
    public long getWaitingDays() {
        return ChronoUnit.DAYS.between(this.reserveDate, LocalDateTime.now());
    }
}